package singleton;

import java.io.Serializable;
import java.util.concurrent.locks.LockSupport;

/**
 * @program: javase
 * @description: 懒汉式
 * @author: luolidong
 * @create: 2021-06-12 15:24
 * @version: 1.0
 */
public class Singleton2 implements Serializable {
    /* 禁止反射通过new创建对象*/
    private Singleton2() {
        if(instance!=null){
            throw new RuntimeException("禁止反射创建对象");
        }
        System.out.println("Singleton2 无参构造");
    }

//    public static Singleton2 instance = null;

    /*   多线程存在线程安全问题
        public static Singleton2 getInstance() {
            if (instance == null) {
                instance = new Singleton2();
            }
            return instance;
        }
     */
/*   每次都判断同步，而只需要赋值一次，效率太低
    public static synchronized Singleton2 getInstance() {
        if (instance == null) {
            instance = new Singleton2();
        }
        return instance;
    }

 */
//  volatile 可见性
    private static volatile Singleton2 instance;
    //双层检查锁
    public static Singleton2 getInstance() {
        /*第一次判空，保证为空才获取锁，提高效率*/
        if (instance == null) {//   1
            synchronized (Singleton2.class) {
                /*多个线程来，如果当前线程还没new对象，而此时另一个线程也进入第一个if,又会new新对象*/
                if (instance == null) {
                    /*
                    * instance = new Singleton2();
                    * 指令重排序
                    * 1.为对象分配内存空间
                    * 2.调用构造方法初始化
                    * 3.将instance指向该内存空间
                    * 可能排序为 1 3 2
                    *  出现问题：一个线程还没完全初始化，让另一个线程认为instance ！= null，
                    *           直接就返回了没有初始化的对象
                    * 解决办法：instance加volatile, 禁止上面指令重排序
                    */
                    instance = new Singleton2();

                }
            }
        }
        return instance;
    }

    /*如果反序列化时定义了readResolve()方法、则会通过该方法返回对象的实例，
    而不是再序列化一个新对象返回、所以能保持返回的是同一对象的实例。
     */
//    private Object readResolve() {
//        return instance;
//    }
}
